﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using LockCrypt.Core;
using Lime49;

namespace LockCrypt.DAL.Exporters {
    /// <summary>
    /// Exports to HTML.
    /// </summary>
    public class HTMLExporter : IDatabaseExporter {
        /// <summary>
        /// Gets or sets the logger to use.
        /// </summary>
        /// <value>The logger.</value>
        public ILogProvider Logger { get; set; }

        /// <summary>
        /// Gets or sets the filename to which to write.
        /// </summary>
        /// <value>The name of the file to which to write.</value>
        public string FileName { get; set; }

        /// <summary>
        /// Initializes a new <see cref="HTMLExporter"/>.
        /// </summary>
        /// <param name="fileName">Name of the file to which to write.</param>
        public HTMLExporter(string fileName) {
            Logger = new NullLogger();
            this.FileName = fileName;
        }

        /// <summary>
        /// Exports the database.
        /// </summary>
        /// <param name="contents">The contents to export.</param>
        public void ExportDatabase(DatabaseContents contents) {
            StringBuilder sb = new StringBuilder();
            sb.Append(@"<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">
            <html>
          <head>
            <title>").Append(I18nUtils.GetString("Strings", "LockCryptAccounts")).Append(@"</title>
            <meta name=""generator"" content=""LockCrypt ").Append(Constants.GetVersion().ToString(3)).Append(@" by Harry Jennerway""/>
            <style type=""text/css"">
            *{margin:0;padding:0;outline:0}
            html, body {
                height:100%;
                min-height:100%
            }
            body {
                font-size:62.5%;
                font-family:Verdana,Arial,Sans-Serif,Helvetica;
                background: #f9f9f9;
                color: #000;
            }
            #wrapper {
                margin: 0 auto;
                background: #F9E8A3;
                width: 50%;
                padding: 1em;
                font-size: 1.1em;
                border: 1px solid #444;
                border-width: 0 1px;
            }
            .group {
                font-size: 1em;
                margin: 0 auto 2em auto;
                border: 1px solid #666;
                background: #faf4dc;
                padding: 1em;
            }
            .account {
                margin-bottom: 1em;
            }
            .divider {
                text-align: center;
            }
            div.footer {
                text-align: center;
            }
            hr {
                display: none;
            }
            h1 { /* Page title */
                margin: 0.5em 0 1em 0;
                font-size: 2em;
            }
            h2 { /* Group names */
                font-size: 1.9em;
            }
            h3 { /* Account names */
                font-size: 1.6em;
                margin-left: 3em;
            }
            dl {
                margin: 0.2em 1em 2em;
            }
            dt {
                font-weight: bold;
                float: left;
                width: 15em;
                text-align: right;
            }
            dd {
                margin: 0 1em 1em 16em;
            }
          </style>
        </head>
        <body>
            <div id=""wrapper"">
                <h1>").Append(I18nUtils.GetString("Strings", "LockCryptAccounts")).Append("</h1>");

            Dictionary<string, ITemplate> templateIdMap;
            if(contents.Templates == null) {
                templateIdMap = new Dictionary<string, ITemplate>();
            } else {
                templateIdMap = contents.Templates.ToDictionary(t => t.ID);
            }
            var groupIdMap = contents.Groups.ToDictionary(g => g.ID); // <group ID, group>
            var dummyGroup = new GroupBase() { Name = I18nUtils.GetString("Strings", "None") };
            var accountGroups = contents.Accounts.OrderBy(a => a.Name)
                                                 .GroupBy(a => a.ParentID ?? "-1")
                                                 .ToDictionary(a => a.Key != "-1" && groupIdMap.ContainsKey(a.Key) ? groupIdMap[a.Key] : dummyGroup, g => g.ToList());

            Logger.Log(string.Format("{0} accounts, {1} groups to export", contents.Accounts.Count, contents.Groups.Count), StatusMessage.StatusMessageType.Status);
            foreach(KeyValuePair<IGroup, List<IAccount>> pair in accountGroups) {
                sb.Append(@"
                <div class=""group"">
                    ").AppendFormat("<h2>{0}</h2>", HtmlUtils.HtmlEncode(pair.Key.Name));
                int alt = 0,
                    lastIndex = pair.Value.Count -1;
                foreach(var account in pair.Value) {
                    string templateName = null;
                    if(account.Template != null) {
                        if(account.Template.Name != null) {
                            templateName = account.Template.Name;
                        } else if(account.Template.ID != null && templateIdMap.ContainsKey(account.Template.ID)) {
                            templateName = templateIdMap[account.Template.ID].Name;
                        }
                    }
                    sb.Append(@"
                        <div class=""account").Append(alt % 2 == 0 ? " alt" : string.Empty).Append(@""">
                            ").AppendFormat("<h3>{0}</h3>", HtmlUtils.HtmlEncode(account.Name)).Append(@"
                            <dl>
                                    ").AppendFormat("<dt>{0}</dt><dd>{1}</dd>\n", I18nUtils.GetString("Strings", "Template"), HtmlUtils.HtmlEncode(templateName ?? I18nUtils.GetString("Strings", "None")));
                    foreach(IField field in account.Fields) {
                        if(string.IsNullOrEmpty(field.Value))
                            continue;
                        if(FieldBase.GetMetaState(field.Meta, FieldMetaData.Url)) {
                            sb.AppendFormat("<dt>{0}</dt><dd><a href=\"{1}\">{1}</a></dd>\n", HtmlUtils.HtmlEncode(field.Name), HtmlUtils.HtmlEncode(field.Value));
                        } else {
                            sb.AppendFormat("<dt>{0}</dt><dd>{1}</dd>\n", HtmlUtils.HtmlEncode(field.Name), HtmlUtils.HtmlEncode(field.Value));
                        }
                    }
                    sb.Append(@"
                            </dl>");
                    if(!string.IsNullOrEmpty(account.Notes)) {
                        sb.AppendFormat("\n<p>{0}</p>", HtmlUtils.HtmlEncode(account.Notes).Replace("\r", "\n").Replace("\n\n", "</p><p>").Replace("\n", "<br/>"));
                    }
                    sb.Append(@"
                        </div>");
                    if(alt < lastIndex) {
                        sb.Append("\n<p class=\"divider\">&diams;&nbsp;&diams;&nbsp;&diams;</p><hr />\n");
                    }
                    Logger.Log(string.Format("Exported {0}", account.Name, StatusMessage.StatusMessageType.Success));
                    alt++;
                }
                sb.Append("</div>");
            }
            sb.Append(@"
            	<!-- Every time you remove a copyright notice, God kills a kitten. Please, think of the kittens. -->
                <div class=""footer"">
	                <p>Generated by <a href=""http://www.lockcrypt.com/"">LockCrypt ").Append(Constants.GetVersion().ToString(3)).Append(@"</a></p>
	                <p>&copy; 2008 - 2010 Harry Jennerway</p>
                </div>
            </div></body></html>");
            File.WriteAllText(FileName, sb.ToString(), Encoding.UTF8);
        }
    }
}
